package multi_thread.master.lock_aqs;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Cheng Jun
 * Description: 基于Lock 体系下的 等待/通知 模式
 * Where a Lock replaces the use of synchronized methods and statements,
 * a Condition replaces the use of the Object monitor methods.
 * To obtain a Condition instance for a particular Lock instance use its newCondition() method.
 * await系列方法 就和 Object 的wait 系列方法一样，signal 系列方法和 notify 系列方法 一样。
 * await/signal 和 wait/notify 一样必须在 获取锁后 运行。
 * 但是 对于同一把锁 Lock 可以生成多个 Condition
 * 各个 condition 之间不会相互影响
 * @version 1.0
 * @date 2021/10/28 21:52
 */
public class ConditionExample {

    public static void main(String[] args) throws InterruptedException {
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition = reentrantLock.newCondition();

        Thread thread0 = new Thread(() -> {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName() + " lock()，上锁成功");
            try {
                System.out.println(Thread.currentThread().getName() + " await()，等待");
                // 和 wait 方法一样 等待5秒后，尝试获取锁，如果获取成功就继续执行
                // 如果在等待时就被 signal 方法通知了，可以提前尝试获取锁。
                condition.await(5, TimeUnit.SECONDS);
                System.out.println(Thread.currentThread().getName() + " 继续执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            reentrantLock.unlock();
        });

        Thread thread1 = new Thread(() -> {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName() + " lock()，上锁成功");
            // signal 不会释放锁，和 notify 方法一样，只表示会在锁被释放（ unlock()方法被调用 ）的时候发出通知
            // 如果没有 unlock()的话，该线程会一直持有锁，其它线程就不会继续执行
            // 同时，要注意到和 notify 一样，在调用时，该线程必须持有锁，不能在锁被释放后再调用
            condition.signal();
            reentrantLock.unlock();
        });

        // 等待线程是放在双向链表，为什么是双向链表，java.util.concurrent.locks.AbstractQueuedSynchronizer.Node
        // 可以查找 pre 节点的使用情况，如：取消前面节点的获取

    }
}
